package com.floreantpos.ui.report;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.jdesktop.swingx.calendar.DateUtils;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRTableModelDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.view.JRViewer;

import com.floreantpos.main.Application;
import com.floreantpos.model.Guest;
import com.floreantpos.model.Ticket;
import com.floreantpos.model.TicketItem;
import com.floreantpos.model.TicketItemModifier;
import com.floreantpos.model.TicketItemModifierGroup;
import com.floreantpos.model.dao.GuestDAO;
import com.floreantpos.model.dao.TicketDAO;
import com.floreantpos.report.ReportItem;
import com.floreantpos.report.SalesReportModel;
import com.floreantpos.report.SalesReportModelFactory;
import com.floreantpos.report.services.ReportService;
import java.util.Collections;
import java.util.Comparator;

public class GuestSalesReport extends Report {

  private SalesReportModel itemReportModel;
  
  private String guestName = "";
  private String guestPhone = "";

  public GuestSalesReport() {
    super();
  }

  @Override
  public void refresh() throws Exception {
    createModels();

    SalesReportModel itemReportModel = this.itemReportModel;

    JasperReport itemReport = (JasperReport) JRLoader.loadObject(SalesReportModelFactory.class.getResource("/com/floreantpos/ui/report/sales_sub_report.jasper"));

    HashMap map = new HashMap();
    ReportUtil.populateRestaurantProperties(map);
    map.put("reportTitle", "==================== Relatório de Vendas por Cliente ====================");
    map.put("reportTime", ReportService.formatFullDate(new Date()));
    map.put("dateRange", ReportService.formatShortDate(getStartDate()) + " até " + ReportService.formatShortDate(getEndDate()));
    map.put("terminalName", com.floreantpos.POSConstants.ALL);
    map.put("itemDataSource", new JRTableModelDataSource(itemReportModel));
    map.put("currencySymbol", Application.getCurrencySymbol());
    map.put("itemGrandTotal", itemReportModel.getGrandTotalAsString());
    map.put("guestName", guestName);
    map.put("guestPhone", guestPhone);
    map.put("itemReport", itemReport);

    JasperReport masterReport = (JasperReport) JRLoader.loadObject(SalesReport.class.getResource("/com/floreantpos/ui/report/guest_sales_report.jasper"));

    JasperPrint print = JasperFillManager.fillReport(masterReport, map, new JREmptyDataSource());
    viewer = new JRViewer(print);
  }

  @Override
  public boolean isDateRangeSupported() {
    return true;
  }

  @Override
  public boolean isTypeSupported() {
    return true;
  }

  public void createModels() {
    Date date1 = DateUtils.startOfDay(getStartDate());
    Date date2 = DateUtils.endOfDay(getEndDate());
    
    Integer guestId = getGuestId();
    
    GuestDAO guestDao = GuestDAO.getInstance();
    Guest guest = guestDao.get(guestId);
    
    if (guest != null) {
      guestName = guest.getName();
      guestPhone = guest.getTelephone();
    }

    List<Ticket> tickets = TicketDAO.getInstance().findGuestTickets(date1, date2, (getReportType() == Report.REPORT_TYPE_1 ? true : false), guestId);

    HashMap<String, ReportItem> itemMap = new HashMap<String, ReportItem>();

    for (Iterator iter = tickets.iterator(); iter.hasNext();) {
      Ticket ticket = (Ticket) iter.next();
      ticket = TicketDAO.getInstance().initializeTicket(ticket);

      List<TicketItem> ticketItems = ticket.getTicketItems();
      if (ticketItems == null) {
        continue;
      }

      String key = null;
      Double unitPrice = Double.valueOf(0);
      
      for (TicketItem ticketItem : ticketItems) {

        Boolean isPizza = false;

        if (ticketItem.isHasModifiers() && ticketItem.getTicketItemModifierGroups() != null) {
          List<TicketItemModifierGroup> ticketItemModifierGroups = ticketItem.getTicketItemModifierGroups();
          for (TicketItemModifierGroup ticketItemModifierGroup : ticketItemModifierGroups) {
            List<TicketItemModifier> modifiers = ticketItemModifierGroup.getTicketItemModifiers();
            for (TicketItemModifier modifier : modifiers) {
              if (modifier.isPizzaModifier()) {
                isPizza = true;
              }
            }
          }
        }

        if (!isPizza) {
          if (ticketItem.getItemId() == null) {
            key = ticketItem.getName();
          } else {
            key = ticketItem.getItemId().toString();
          }
          ReportItem reportItem = itemMap.get(key);

          if (reportItem == null) {
            reportItem = new ReportItem();
            reportItem.setId(key);
            reportItem.setPrice(ticketItem.getUnitPrice());
            reportItem.setName(ticketItem.getName());
            reportItem.setTaxRate(ticketItem.getTaxRate());

            itemMap.put(key, reportItem);
          }
          reportItem.setQuantity(ticketItem.getItemCount() + reportItem.getQuantity());
          reportItem.setTotal(reportItem.getTotal() + ticketItem.getSubtotalAmountWithoutModifiers());
        }

        String pizzaName = "";

        if (ticketItem.isHasModifiers() && ticketItem.getTicketItemModifierGroups() != null) {
          List<TicketItemModifierGroup> ticketItemModifierGroups = ticketItem.getTicketItemModifierGroups();
          for (TicketItemModifierGroup ticketItemModifierGroup : ticketItemModifierGroups) {

            pizzaName = ticketItemModifierGroup.getParent().getName();

            List<TicketItemModifier> modifiers = ticketItemModifierGroup.getTicketItemModifiers();

            Collections.sort(modifiers, new Comparator() {
              public int compare(Object o1, Object o2) {
                TicketItemModifier c1 = (TicketItemModifier) o1;
                TicketItemModifier c2 = (TicketItemModifier) o2;
                return c1.toString().compareTo(c2.toString());
              }
            });

            for (TicketItemModifier modifier : modifiers) {
              if (modifier.isPizzaModifier()) {
                pizzaName = pizzaName + " " + modifier.getName();
              }
            }

            for (TicketItemModifier modifier : modifiers) {
              if (modifier.isPizzaModifier() && modifier.getUnitPrice() == 0) {
                // Ignore Pizzas with no value 
                // Pizzas with no value = Pizzas with more than one topping/flavor (only one of the toppings accrues the entire Pizza value)
                // The report only accrues data from the Pizza with value
              } else {
                if (modifier.isPizzaModifier()) {
                  key = pizzaName.trim();
                  unitPrice = modifier.getUnitPrice() + ticketItem.getUnitPrice();
                } else {
                  key = modifier.getName() + " (" + ticketItem.getName() + ")";
                  unitPrice = modifier.getUnitPrice();
                } 
                ReportItem modifierReportItem = itemMap.get(key);
                if (modifierReportItem == null) {
                  modifierReportItem = new ReportItem();
                  modifierReportItem.setId(key);
                  modifierReportItem.setPrice(unitPrice);
                  modifierReportItem.setName(key);
                  modifierReportItem.setTaxRate(modifier.getTaxRate());
                  itemMap.put(key, modifierReportItem);
                }
                modifierReportItem.setQuantity(modifierReportItem.getQuantity() + modifier.getItemCount());
                modifierReportItem.setTotal(modifierReportItem.getTotal() + modifier.getItemCount() * unitPrice);
              }
            }
          }
        }
      }
      ticket = null;
      iter.remove();
    }
    itemReportModel = new SalesReportModel();
    itemReportModel.setItems(new ArrayList<ReportItem>(itemMap.values()));
    itemReportModel.calculateGrandTotal();
  }
}
